/**
 * O : 정합정 검사엔진<br>
 *
 * @classDescription eGovXF UI Validation Core Engine
 * @author nayasis
 * @since  2011-05-16
 * @private
 */
xu.z_vdCore = {

  rulePool : [], // 규칙목록 (인덱스 별)
  chkPool  : [], // 검사목록 (인덱스 별)
  observe  : [], // 감시목록 (전체)

  checkBlurEvent : true, // Blur 이벤트 발생시 체크를 계속 진행하기 위한 flag

  /**
   * 개체를 생성한다.
   * @return {Number} 개체 index
   */
  getInstance : function() {

    xu.z_vdCore.rulePool.push( {} );

    return xu.z_vdCore.rulePool.length - 1;

  },

  /**
   * 정합성 체크엔진을 구동한다.
   * @param {Number} idx rule 인덱스
   */
  init : function( idx ) {

    this.rulePool[idx].init = true;

    this.chkPool[ idx ] = {};
    this.chkPool[ idx ].rule = [];

    for( var exp in this.rulePool[idx].rule ) {

      $(exp).each( function(){
        xu.z_vdCore.setChkPool( xu.window.getId(this), exp );
      });

      $(exp)
        .die( "blur.xuValid" )
        .die( "focus.xuValid" )
        .die( "liveCreate.xuValid" )
        .live( "liveCreate.xuValid", $.proxy(this, "liveCreate") )
        .live( "blur.xuValid",       $.proxy(this, "blur")       )
        .live( "focus.xuValid",      $.proxy(this, "focus")      );

    }

  },

  /**
   * 입력받은 모든 데이터에 대해서 정합성 엔진을 초기화한다.
   */
  initAll : function() {
    for( var i = 0, cnt = xu.z_vdCore.rulePool.length; i < cnt; i++ ) {
      xu.z_vdCore.init( i );
    }
  },

  /**
   * F: 정합성 검사결과를 화면에 출력한다.
   *
   * @param {Object} result 정합성 검사결과
   */
  showValidResult : function( id, result ) {

    if( xu.c.VALIDATOR.SHOW_TIP != true ) return;

    if( result.msg.length == 0 ) {
      xu.window.hideTip();
    } else {
      xu.window.showTip( result.msg, {id:id} );
    }

  },

  /**
   * 검사목록에 활성화된 INPUT 객체의 Validation 규칙을 추가한다.
   * @param {String} id       활성화된 INPUT 객체의 id
   * @param {String} selector 셀렉터
   */
  setChkPool : function( id, selector ) {

    for( var i = 0, iCnt = this.rulePool.length; i < iCnt; i++ ) {

      if( xu.chk.isNull(this.chkPool[i]) ) continue;

      var param = this.rulePool[i].rule[selector];

      if( xu.chk.isNull(param) ) continue;

      var chkParam = this.chkPool[i].rule[id];

      if( xu.chk.isNull(chkParam) ) {

        this.chkPool[i].rule[id] = param;
        this.setObserveRule( id, param );

      }

    }

  },

  /**
   * 감시목록에 활성화된 INPUT 객체의 Validation 규칙을 추가한다.
   *
   * @param {String} id
   * @param {xu.data} param  검사할 규칙
   */
  setObserveRule : function( id, param ) {

    var flag = false;

    if( xu.chk.isNull(this.observe[id]) ) {
      this.observe[id] = {};
      this.observe[id].rule = param;
      this.observe[id].val  = $("#"+id).val();
      this.observe[id].observed = false;

      flag = true;

    } else if( ! this.observe[id].rule.equals(param) )  {
      this.observe[id].rule.merge( param );
      flag = true;
    }

    if( flag == true ) {

      var chkResult = this.chkValid( $("#"+id).val(), this.observe[id].rule );

      var obj = $("#"+id);

      for( var attr in this.observe[id].rule.getData() ) {

        switch( attr.toLowerCase() ) {
          case "maxlen" :
          case "maxbyt" :
          case "fixlen" :
          case "fixbyt" :
            obj.prop( "maxlength", param.get(attr) );
            break;
          case "mask" :
            obj.prop( "maxlength", param.get(attr).length );
            break;
          case "date" :

            var dtFormat = param.get(attr).format;
            var dtFn     = param.get(attr).fn;

            obj.datepicker({
              showButtonPanel : true,
              buttonImage     : xu.c.ROOT_PATH + xu.c.DATE.PICKER_BTN_IMG,
              onSelect        : function( dateText, param ) {
                var preDate = xu.date( param.lastVal, dtFormat );
                var selDate = xu.date( dateText, xu.c.DATE.FORMAT );
                var newDate = new Date( selDate.getYear(), selDate.getMonth() - 1, selDate.getDate(), preDate.getHour(), preDate.getMin(), preDate.getSec(), 1 );
                $( "#"+param.id ).val( xu.date(newDate, dtFormat).toString() );
                dtFn( dateText, param );
              }
            });
            obj.prop( "maxlength", dtFormat.length );
            obj.next().prop( "id", id + "Pick" ).css({ "margin-left" : "3px", "vertical-align" : "-5px" });

            break;
        }
      }

    }

  },

  /**
   * 동적으로 생성될 때 실행될 이벤트
   * @param {Object} event
   */
  liveCreate : function( event ) {

    var selector = event.handleObj.selector;
    var id       = xu.window.getId( event.currentTarget );
    var self     = $("#"+id);

    if( self.prop("liveCreated") != true ) {
      this.setChkPool( id, selector );
      self.prop( "liveCreated", true );
    }

  },

  /**
   * 포커스 로직을 처리한다.
   * @param {Object} event
   */
  focus : function( event ) {

    this.liveCreate( event );

    var selector = event.handleObj.selector;
    var id       = xu.window.getId( event.currentTarget );

    var chkParam  = this.observe[id].rule;
    var chkResult = this.chkValid( $("#"+id).val(), chkParam );

    this.showValidResult( id, chkResult );

    // 포커스 상태에 들어갈 경우 감시 이벤트 활성화
    this.observe[id].observed = true;
    this.observe[id].preVal = $("#"+id).val();

    this.keyObserve( id );

  },

  /**
   * 입력상자에서 포커스가 빠져나갔을 경우 이벤트를 처리한다.
   * @param {Object} event
   */
  blur : function( event ) {

    xu.window.hideTip();

    if( this.checkBlurEvent == false ) return false;

    var id  = $(event.currentTarget).prop("id");
    var obj = $("#"+id);

    // 감시 제거
    this.observe[id].observed = false;

    var chkRule = this.observe[id].rule;

    // focus-out 시 정합성 체크
    var chkRslt = this.chkValid( obj.val(), chkRule );

    // xu.msg.debug( "xu.c.VALIDATOR.SHOW_ALERT : " + xu.c.VALIDATOR.SHOW_ALERT );

    if( xu.c.VALIDATOR.SHOW_ALERT && ! chkRslt.result ) {

      this.checkBlurEvent = false;

      setTimeout( function(){
        xu.z_vdCore.showErrorMsg( id, xu.z_vdCore.getUserFriendlyMsg( chkRslt ) );
        $("#"+id).focus();
        xu.z_vdCore.checkBlurEvent = true;
      }, 0 );

    }

    // 입력값에 mask 적용
    if( chkRule.hasKey("mask") ) {

      var mask   = chkRule.get("mask");
      var mskVal = xu.str(obj).setUnmask(mask).setMask(mask).val();

      obj.val(mskVal);
      xu.z_vdCore.observe[id].val = mskVal;

    } else if( chkRule.hasKey("date") ) {

      var format = chkRule.get( "date" ).format;
      var date   = xu.date( obj.val(), format );
      if( date.val() != null ) obj.val( date.toString() );

    }

  },

  /**
   * 키 입력 이벤트를 지속적으로 감시한다.
   * @param {xu.data} id
   */
  keyObserve : function( id ) {

    // 감시상태가 아니라면 함수 종료
    if( this.observe[id].observed != true ) return;

    var obj = $( "#" + id );

    // 입력값이 바뀔 때까지 기다린다.
    if (xu.z_vdCore.observe[id].val == obj.val()) {
      setTimeout( function(){ xu.z_vdCore.keyObserve(id); }, xu.c.VALIDATOR.CHECK_INTERVAL );
      return false;
    }

    this.observe[id].preVal = this.observe[id].val;
    this.observe[id].val    = obj.val();

    // 검사를 수행한다.
    var chkParam  = this.observe[id].rule;
    var chkResult = this.chkValid( obj.val(), chkParam );

    this.showValidResult( id, chkResult );

    // 입력값을 다시 체크한다.
    if( this.observe[id].observed != true ) return;
    setTimeout( function(){ xu.z_vdCore.keyObserve(id); }, xu.c.VALIDATOR.CHECK_INTERVAL );

  },

  /**
   * id에 해당하는 오브젝트의 validation을 수행한다.<br>
   * @param {String} 정합성 검사를 수행할 값
   * @param {xu.data} rule 정합성 규칙
   * @return {Object} 수행결과를 담은 JSON 데이터 {result:true/false, msg:[에러메세지], rule:[검사한 규칙], param:[규칙에 설정한 파라미터], chkVal:[검사한 값] }
   */
  chkValid : function( chkVal, rule ) {

    var result = {};
    result.result = true;
    result.msg    = [];
    result.rule   = [];
    result.param  = [];
    result.chkVal = [];

    var param, errMsg;

    var opt = rule.getData();

    for( var attr in opt ) {

      param  = opt[ attr ];
      errMsg = "";

      switch( attr ) {
        case "required" :
          if( xu.chk.isEmpty(chkVal) ) errMsg = getMsg( attr );
          break;
        case "minlen" :
          if( !xu.chk.isMinLen(xu.str(chkVal).clearXss(), param) ) errMsg = getMsg( attr, param, xu.str(chkVal).clearXss().length() );
          break;
        case "maxlen" :
          if( !xu.chk.isMaxLen(xu.str(chkVal).clearXss(), param) ) errMsg = getMsg( attr, param, xu.str(chkVal).clearXss().length() );
          break;
        case "fixlen" :
          if( !xu.chk.isMinLen(xu.str(chkVal).clearXss(), param) || !xu.chk.isMaxLen(xu.str(chkVal).clearXss(), param) ) errMsg = getMsg( attr, param, xu.str(chkVal).clearXss().length() );
          break;
        case "minbyt" :
          if( !xu.chk.isMinByte(xu.str(chkVal).clearXss(), param) ) errMsg = getMsg( attr, param, xu.str(chkVal).clearXss().bytes() );
          break;
        case "maxbyt" :
          if (!xu.chk.isMaxByte(xu.str(chkVal).clearXss(), param)) errMsg = getMsg( attr, param, xu.str(chkVal).clearXss().bytes() );
          break;
        case "fixbyt" :
          if( !xu.chk.isMinByte(xu.str(chkVal).clearXss(), param) || !xu.chk.isMaxByte(xu.str(chkVal).clearXss(), param) ) errMsg = getMsg( attr, param, xu.str(chkVal).clearXss().getByte() );
          break;
        case "num" :
          if( !xu.chk.isEmpty(chkVal) && !xu.chk.isNum(chkVal) ) errMsg = getMsg( attr );
          break;
        case "numeric" :
          if( !xu.chk.isEmpty(chkVal) && !xu.chk.isNumeric(chkVal) ) errMsg = getMsg( attr );
          break;
        case "eng" :
          if( !xu.chk.isEmpty(chkVal) && !xu.chk.isEng(chkVal) ) errMsg = getMsg( attr );
          break;
        case "noe" :
          if( !xu.chk.isEmpty(chkVal) && !xu.chk.isNumEng(chkVal) ) errMsg = getMsg( attr );
          break;
        case "kor" :
          if( !xu.chk.isEmpty(chkVal) && !xu.chk.isKor(chkVal) ) errMsg = getMsg( attr );
          break;
        case "nok" :
          if( !xu.chk.isEmpty(chkVal) && !xu.chk.isKor(chkVal) ) errMsg = getMsg( attr );
          break;
        case "nae" :
          if( !xu.chk.isEmpty(chkVal) && !xu.chk.isNumAndEng(chkVal) ) errMsg = getMsg( attr );
          break;
        case "notnum" :
          if( !xu.chk.isNotNum(chkVal) ) errMsg = getMsg( attr );
          break;
        case "notkor" :
          if( !xu.chk.isNotKor(chkVal) ) errMsg = getMsg( attr );
          break;
        case "date" :
          if( !xu.chk.isEmpty(chkVal) && !xu.chk.isDate(chkVal, param.format) ) errMsg = getMsg( attr );
          break;
        case "psn" :
          if( !xu.chk.isPsn(chkVal) ) errMsg = getMsg( attr );
          break
        case "fsn" :
          if( !xu.chk.isFsn(chkVal) ) errMsg = getMsg( attr );
          break;
        case "csn" :
          if( !xu.chk.isCsn(chkVal) ) errMsg = getMsg( attr );
          break;
        case "lsn" :
          if (!xu.chk.isLsn(chkVal)) errMsg = getMsg( attr );
          break;
        case "email" :
          if( !xu.chk.isEmail(chkVal) ) errMsg = getMsg( attr );
          break;
        case "homephone" :
          if( !xu.chk.isHomePhone(chkVal) ) errMsg = getMsg( attr );
          break;
        case "cellphone" :
          if( !xu.chk.isCellPhone(chkVal) ) errMsg = getMsg( attr );
          break;
        case "mask" :
          if( !xu.chk.isMasked( xu.str(chkVal).setUnmask(param).setMask(param), param) ) errMsg = getMsg( attr, param );
          break;
      }

      if( errMsg != "" ) {
        result.result = false;
        result.msg.push( errMsg );
        result.rule.push( attr );
        result.param.push( param );
        result.chkVal.push( chkVal );
      }

    }

    return result;

    function getMsg( ruleName, param ) {
      arguments[0] = "xu.api.vdRule." + arguments[0];
      return xu.msg.get( arguments );
    }

  },

  /**
   * (ID에 해당하는) 개체의 포맷이 적용되기 이전값을 반환한다.
   * @param {String} id 개체의 ID
   * @return {String}
   */
  getUnmaskedVal : function( id ) {

    var obj = ( xu.chk.isTypStr(id) ) ? $("#"+id) : $(id);
    if( obj.length != 1 ) return "";

    var val = obj.val();
    if( val == "" ) return "";

    var param = xu.z_vdCore.observe[id];

    if( xu.chk.isNull(param) ) return val;

    param = param.getData();

    for( var attr in param ) {

      switch( attr ) {
        case "date" :

          var d = xu.date( val );
          var f = xu.str( d.format() ).remove( /[-|.|:| ]/g ).val();

          return d.toString( f );

        case "mask" :

          return xu.str( val ).setUnmask( param[attr] ).val();

        default :
      }

    }

    return val;

  },

  /**
   * 특정 id를 가진 객체를 대상으로 에러메세지를 출력한다.
   *
   * @param {String} id   에러 출력대상 id
   * @param {String} msg  에러메세지
   * @return {Boolean} 에러출력여부
   */
  showErrorMsg : function( id, msg ) {

    if( msg == "" ) return false;

    var title = $("#"+id).prop("title");

    if( title != "" ) {
      msg = "@" + xu.c.REG_PTN.HAN_JOSA[0] + "(" + xu.c.REG_PTN.HAN_JOSA[1] + ") " + msg;
    }

    xu.msg.alert( msg, title );

    return true;

  },


  /**
   * 사용자 친화적인 메세지를 구한다.
   *
   * @param {Object} chkRslt xu.z_vdCore.chkValid 함수 수행결과
   * @return {String} 출력할 에러메세지
   */
  getUserFriendlyMsg : function( chkRslt ) {

    if( chkRslt.result ) return  "";

    var idx = 0, msg = "";

    for( var z = 0; z <= 1; z++ ) {

      switch( z ) {

        case 0 :
               if( chkRule("required") ) msg = getMsg( "required" );
          else if( chkRule("minlen") )   msg = getMsg( "minlen", chkRslt.param[idx], xu.str(chkRslt.chkVal[idx]).clearXss().length() );
          else if( chkRule("maxlen") )   msg = getMsg( "maxlen", chkRslt.param[idx], xu.str(chkRslt.chkVal[idx]).clearXss().length() );
          else if( chkRule("fixlen") )   msg = getMsg( "fixlen", chkRslt.param[idx], xu.str(chkRslt.chkVal[idx]).clearXss().length() );
          else if( chkRule("minbyt") )   msg = getMsg( "minlen", chkRslt.param[idx], xu.str(chkRslt.chkVal[idx]).clearXss().bytes() );
          else if( chkRule("maxbyt") )   msg = getMsg( "maxlen", chkRslt.param[idx], xu.str(chkRslt.chkVal[idx]).clearXss().bytes() );
          else if( chkRule("fixbyt") )   msg = getMsg( "fixlen", chkRslt.param[idx], xu.str(chkRslt.chkVal[idx]).clearXss().bytes() );
          else if( chkRule("numeric") )  msg = getMsg( "numeric" );
          else if( chkRule("num") )      msg = getMsg( "num" );
          else if( chkRule("eng") )      msg = getMsg( "eng" );
          else if( chkRule("noe") )      msg = getMsg( "noe" );
          else if( chkRule("kor") )      msg = getMsg( "kor" );
          else if( chkRule("nok") )      msg = getMsg( "nok" );
          else if( chkRule("nae") )      msg = getMsg( "nae" );
          else if( chkRule("notnum") )   msg = getMsg( "notnum" );
          else if( chkRule("notkor") )   msg = getMsg( "notkor" );
          else if( chkRule("date") )     msg = getMsg( "date" );
          break;

        case 1 :
               if( chkRule("psn") )      msg = getMsg( "psn" );
          else if( chkRule("fsn") )      msg = getMsg( "fsn" );
          else if( chkRule("csn") )      msg = getMsg( "csn" );
          else if( chkRule("lsn") )      msg = getMsg( "lsn" );
          else if( chkRule("email") )    msg = getMsg( "email" );
          else if( chkRule("homephone")) msg = getMsg( "homephone" );
          else if( chkRule("cellphone")) msg = getMsg( "cellphone" );
          else if( chkRule("mask") )     msg = getMsg( "mask", chkRslt.param[idx] );

          break;
      }

      if( msg != "" ) return msg;

    }

    return "";

    function chkRule( ruleName ) {
      idx = $.inArray( ruleName, chkRslt.rule );
      return idx >= 0;
    }

    function getMsg( ruleName, param ) {
      arguments[0] = "xu.api.vdMsg." + arguments[0];
      return xu.msg.get( arguments );
    }


  },

  /**
   * 동적 생성 객체를 감시목록에 추가한다.
   *
   * @param {Number} idx rule 인덱스
   */
  refresh : function( idx ) {

    var idFocused = xu.window.getFocusId();

    if( this.rulePool[idx].init != true ) return;

    for( var exp in this.rulePool[idx].rule ) {
      $(exp).trigger( "liveCreate.xuValid" );
    }

    $("#"+idFocused).focus();

  },

  /**
   * 감시그룹에 속한 모든 동적 생성 객체를 감시목록에 추가한다.
   */
  refreshAll : function() {

    for( var i = 0, cnt = this.rulePool.length; i < cnt; i++ ) {
      this.refresh( i );
    }

  }

}


/**
 * F: 입력항목의 validation 처리를 관리하는 클래스.
 *
 * <pre>
 *
 * // 객체 선언
 * var group = xu.validator();
 *
 * // 규칙 선언
 * group.add("#inpDate", {date:true} ).add( "[name^=item]", {required:true} ).init();
 *
 * // 정합성 검사
 * group.isValid();
 *
 * </pre>
 *
 * @author 정화수, 2011.06.14
 * @return {xu.validator}
 * @classDescription 입력항목의 validation 처리를 관리하는 클래스
 */
xu.validator = function() {

  var z_self = arguments.callee;
  if(!(this instanceof z_self)) return new z_self();

  this.idx      = xu.z_vdCore.getInstance();
  this.rulePool = xu.z_vdCore.rulePool[ this.idx ];

}

xu.validator.prototype = {

  /**
   * 정합정 체크로직을 세팅한다.<br><br>
   *
   * @param {String} expression 셀렉터
   * @param {Object} param 정합성 체크옵션
   * <pre>
   * required  : {Boolean} 필수입력
   * minlen    : {Number}  최소길이
   * maxlen    : {Number}  최대길이
   * minbyt    : {Number}  최소글자
   * maxbyt    : {Number}  최대글자
   * fixlen    : {Number}  고정길이
   * fixbyt    : {Number}  고정글자
   * date      : {String}  날짜포맷 (YYYY-MM-DD HH:MI:SS)
   * date      : {Array}   [ 날짜포맷 (YYYY-MM-DD HH:MI:SS), 실행함수 ]
   * psn       : {Boolean} 주민등록번호
   * email     : {Boolean} 이메일
   * homephone : {Boolean} 집전화번호
   * cellphone : {Boolean} 휴대전화번호
   * numeric   : {Boolean} 수치자료만 허용 (소수점을 포함할 경우도 가능)
   * num       : {Boolean} 숫자만 허용
   * eng       : {Boolean} 영문만 허용
   * kor       : {Boolean} 한글만 허용
   * noe       : {Boolean} 영문숫자만 허용
   * nae       : {Boolean} 영문&숫자만 허용
   * nok       : {Boolean} 한글숫자만 허용
   * notnum    : {Boolean} 숫자 비허용
   * notkor    : {Boolean} 한글 비허용
   * mask      : {String}  패턴 (X:문자, 9:숫자, *:문자 또는 숫자)
   * fsn       : {Boolean} 국내거소신고번호
   * csn       : {Boolean} 사업자등록번호
   * lsn       : {Boolean} 법인등록번호
   * </pre>
   * @return {xu.validator}
   */
  add : function( expression, param ) {

    if( xu.chk.isNull(param) || xu.chk.isEmpty(expression) ) return this;

    this.rulePool.rule = this.rulePool.rule || [];

    var realParam = new xu.data();

    for( var i in param ) {

      var attr = i.toLowerCase();

      switch( attr ) {
        case "required"  :
        case "psn"       :
        case "email"     :
        case "homephone" :
        case "cellphone" :
        case "num"       :
        case "numeric"   :
        case "eng"       :
        case "noe"       :
        case "kor"       :
        case "nok"       :
        case "notnum"    :
        case "notkor"    :
        case "fsn"       :
        case "csn"       :
        case "nae"       :
        case "lsn"       :
          if( param[i] != true ) continue;
          break;
        case "minlen"    :
        case "maxlen"    :
        case "minbyt"    :
        case "maxbyt"    :
        case "fixlen"    :
        case "fixbyt"    :
          if( !xu.chk.isNum(param[i]) ) continue;
          break;
        case "date"      :

          var dtFormat = xu.c.DATE.FORMAT;
          var dtFn     = function() {};

          if( xu.chk.isTypStr(param[i]) ) {
            dtFormat = param[i];
          } else if( xu.chk.isTypStr(param[i]) ) {
            dtFn = param[i];
          } else if( xu.chk.isTypArr(param[i]) ) {

            for( var z = 0, zCnt = param[i].length; z < zCnt; z++ ) {

              if( xu.chk.isTypStr(param[i][z]) ) {
                dtFormat = param[i][z];
              } else if( xu.chk.isTypFn(param[i][z]) ) {
                dtFn = param[i][z];
              }

            }

          }

          param[i] = {};
          param[i].format = dtFormat;
          param[i].fn     = dtFn;

          break;
        default :
          if( xu.chk.isEmpty(param[i]) ) continue;
          break;
      }

      realParam.add( attr, param[i] );

    }

    if( realParam.size() > 0 ) {
      this.rulePool.rule[ expression ] = realParam;
    }

    return this;

  },

  /**
   * 입력항목의 정합성 여부를 확인한다.
   * @param {Boolean} showAlert 알람창 출력여부
   * @return {Boolean} 정합성 검사 성공여부
   */
  isValid : function( showAlert ) {

    if( showAlert != false ) showAlert = true;

    this.refresh();

    var chkPool = xu.z_vdCore.chkPool[this.idx];

    for( var id in chkPool.rule ) {

      if( $("#"+id).length == 0  ) {
        delete chkPool.rule[id];
        continue;
      }

      var chkRslt =  xu.z_vdCore.chkValid( $("#"+id).val(), chkPool.rule[id] );

      if( chkRslt.result ) continue;

      if( showAlert == true ) {

        var errMsg = xu.z_vdCore.getUserFriendlyMsg( chkRslt );

        xu.z_vdCore.showErrorMsg( id, errMsg );

        $("#"+id).focus();

      }

      return false;

    }

    return true;

  },


  /**
   * validation 엔진을 초기화한다.
   *
   * @param blurAlert     {Boolean} 입력항목의 포커스를 빠져나갈 때, 정합성 체크결과를 즉시 알려줄지 여부 (기본값 : false)
   * @param realtimeAlert {Boolean} 실시간으로 정합성 체크결과를 입력항목 옆에 표시해줄지 여부 (기본값 : false)
   */
  init : function( blurAlert, realtimeAlert ) {

    var idx = this.idx;

    if( $.isReady ) {
      xu.z_vdCore.init( idx );
    } else {
      $().ready( function() {
        xu.z_vdCore.init( idx );
      });
    }

    if( blurAlert     == true ) xu.c.VALIDATOR.SHOW_ALERT = true;
    if( realtimeAlert == true ) xu.c.VALIDATOR.SHOW_TIP   = true;

  },

  /**
   * Validation 엔진의 감시목록을 갱신한다.<br/>
   *
   * 동적으로 생성한 객체가 감시목록규칙에 포함되는 항목이라면,
   * 해당 함수를 프로그램에서 호출하여 정합정 엔진을 갱신해주어야 한다.
   */
  refresh : function() {
    xu.z_vdCore.refresh( this.idx );
  }

}


//jQuery Patch (jQuery UI Datepicker 1.8.14)
//시분초 입력형식 때문에 Picker의 초기 선택값이 항상 현재시간으로 지정되던 문제 수정 (2012.06.29, 정화수 대리)
jQuery(function($){

$.datepicker._setDateFromField = function( inst, noDefault ) {

 if (inst.input.val() == inst.lastVal) {
   return;
 }
 var dateFormat = this._get(inst, 'dateFormat');
 var dates = inst.lastVal = inst.input ? inst.input.val() : null;
 var date, defaultDate;
 date = defaultDate = this._getDefaultDate(inst);
 var settings = this._getFormatConfig(inst);

 // 날짜가 YYYY.MM.DD 포맷이 아닐 경우에도 (시,분,초가 포함되어 있을 경우라 하더라도)
 // Picker의 초기 선택값이 입력상자의 날짜가 되도록 수정 (정화수 대리, 2012.06.29)
 dates = xu.date( dates ).toString();

 try {
   date = this.parseDate(dateFormat, dates, settings) || defaultDate;
 } catch (event) {
   this.log(event);
   dates = (noDefault ? '' : dates);
 }
 inst.selectedDay = date.getDate();
 inst.drawMonth = inst.selectedMonth = date.getMonth();
 inst.drawYear = inst.selectedYear = date.getFullYear();
 inst.currentDay = (dates ? date.getDate() : 0);
 inst.currentMonth = (dates ? date.getMonth() : 0);
 inst.currentYear = (dates ? date.getFullYear() : 0);
 this._adjustInstDate(inst);

};

});